// Couper une cyclide par des plans correspondant aux cercles de Villarceau
// On essaie de rendre le tout un peu plus analytique
// 29/10/2014
// On essaie de tout rapatrier dans ce fichier : 
// - toujours charger le stl de la cyclide (pour verifier)
// - construire les cercles3D ici : 
// on n'a besoin que de la moitie des patterns , pour epsilon=1 par exemple. Les autres sont symetriques (avec des coupures a l'envers
// oui mais non : les intersections interessantes sont entre le cercle C et tous les cercles avec un epsilon oppose. 
// Les intersections des cercles de meme epsilon servent a definir la forme de lunules
// Reprise le 12/12/2014
import ij.IJ;
import ij.ImagePlus;
import ij.gui.NewImage;
import ij.io.FileSaver;
import ij.plugin.PlugIn;
import ij.process.ColorProcessor;
import ij.process.ImageProcessor;


import java.awt.Color;


import java.awt.Font;

import java.awt.Polygon;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.PrintStream;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Locale;
import java.util.Random; 
import java.util.Scanner;



import pluginUtils.CiclydeVillarceauCircle;
import pluginUtils.Circle;
import pluginUtils.Circle3D;
import pluginUtils.CircleArrangement;
import pluginUtils.Complexe; 
import pluginUtils.DoyleCircle;
import pluginUtils.Droite;
import pluginUtils.DupinCyclide;
import pluginUtils.MobiusTransform;
import pluginUtils.CircleInversion;
import pluginUtils.PackCircle;
import pluginUtils.Plane;
import pluginUtils.Pos3D;
import pluginUtils.Sphere;
import pluginUtils.SphereInversion;
import sliceformUtils.CoupleDAngles;
import sliceformUtils.DroiteSpace3D;
import sliceformUtils.Ligne;
import sliceformUtils.Mesh;
import sliceformUtils.STLReader;
import sliceformUtils.Saucisson;
import sliceformUtils.Segment;
import sliceformUtils.Triangle;


public class SliceFormCyclideV6 extends ImagePlus implements PlugIn{
	{Locale.setDefault(Locale.US); }
	
	private ImageProcessor primeIP; 
	private int X=2000,Y=2000; // image size
	
	private DataInputStream input;
	private double xShift=0; 
	private double zShift=0; 
	
	
	

	private Random generator=new Random(); // One always needs some randomness
	
	// Scaling  the image
	private double x0=0,x1=1,y0=0,y1=1;
	private double acoef,ccoef,vcoef,wcoef; 
	
	private static double a,mu,c; 
	private static Pos3D pointCommun; 
	private static double marge=0.5;
	private static int nbCercles=7; 
	private static DroiteSpace3D intersectionsPositifPositif[][];
	private static Pos3D[][][] pointsInterPositifPositif; 
	private static CiclydeVillarceauCircle cerclesPositifs[];
	private static Plane lesPlansPositifs[]; 
	
	private static DroiteSpace3D intersectionsNegatifNegatif[][];
	private static Pos3D[][][] pointsInterNegatifNegatif; 
	private static CiclydeVillarceauCircle cerclesNegatifs[];
	private static Plane lesPlansNegatifs[]; 
	
	private static DroiteSpace3D intersectionsPositifNegatif[][];
	private static Pos3D[][][] pointsInterPositifNegatif; 
	
	private static DroiteSpace3D intersectionsNegatifPositif[][];
	private static Pos3D[][][] pointsInterNegatifPositif; 
	
	
	public void setCoefs(){
		acoef=X/(x1-x0); 
		vcoef=Y/(y1-y0); 
		ccoef=-acoef*x0; 
		wcoef=-vcoef*y0; 
	}
	 
	
	
	public void setBounds(double xl,double xu,double yl,double yu){
		x0=xl; 
		x1=xu;
		y0=yl;
		y1=yu; 
	}
	
	private void drawCircle(Circle3D c,ImageProcessor i1){
		double xCenter=c.getCenter().getY(); 
		double yCenter=c.getCenter().getZ(); 
		//if(c.getRadius()<0.001) return ; 
		
		int intX=(int)((xCenter-xShift)*acoef+ccoef);
		int intY=(int)((yCenter-zShift)*vcoef+wcoef);
		int intRx=(int)(c.getRayon()*acoef);
		int intRy=(int)(c.getRayon()*vcoef);
		
		
		i1.drawOval(intX-intRx,intY-intRy,intRx*2,intRy*2);
	}
	
	private void drawPoint(double x,double y, ImageProcessor ip){
		int intX=(int)(x*acoef+ccoef);
		int intY=(int)(y*vcoef+wcoef);
		ip.fillOval(intX-3,intY-3,6,6);
	}
	
	private void drawChaine(double x,double y,String s,ImageProcessor ip){
		int intX=(int)(x*acoef+ccoef);
		int intY=(int)(y*vcoef+wcoef);
		ip.drawString(s,intX,intY);
	}
	
	private void drawLine(double xd,double yd,double xf,double yf){
		int XD=(int)(xd*acoef+ccoef); 
		int YD=(int)(yd*vcoef+wcoef); 
		int XF=(int)(xf*acoef+ccoef); 
		int YF=(int)(yf*vcoef+wcoef);
		primeIP.drawLine(XD,YD,XF,YF); 
	}
	
	private void drawLine(double xd,double yd,double xf,double yf,ImageProcessor ip){
		int XD=(int)(xd*acoef+ccoef); 
		int YD=(int)(yd*vcoef+wcoef); 
		int XF=(int)(xf*acoef+ccoef); 
		int YF=(int)(yf*vcoef+wcoef);
		ip.drawLine(XD,YD,XF,YF); 
	}
	
	// Couper un Mesh par un plan
	public Ligne tranche(Mesh leMesh,Plane lePlan){

		Ligne contour=new Ligne(lePlan);
		Iterator<Triangle> it=leMesh.iterator(); 
		while(it.hasNext()){
			Triangle tr=it.next(); 
			if (tr.isCut(lePlan)) {  contour.add(tr.coupePar(lePlan));}		
		}
		
		//System.out.println("\n Contour :\n"+contour.info()); 
		
		
		return contour;
	}
	
	
	
	public void printPositif(Circle3D leCercle,Pos3D leCentre,CoupleDAngles larot,int numero,String name){
	    name="dupin/dir4/Positif"+name;
	    
		setBounds(2*(-mu-c-marge),2*(mu+c+marge),2*(-mu-c-marge),2*(mu+c+marge)); 
		setCoefs();
		
		ImagePlus gamma=NewImage.createRGBImage (name+numero,X,Y, 1, NewImage.FILL_WHITE);	
		ImageProcessor i1=gamma.getProcessor();
		FileSaver fs=new FileSaver(gamma); 
		i1.setColor(Color.BLACK);
		i1.drawString("Positif "+numero,20,20); 
		//Pos3D translation=Pos3D.sub(Pos3D.ZERO,leCercle.getCenter());
		Pos3D translation=new Pos3D(0,-leCercle.getCenter().getY(),-leCercle.getCenter().getZ());
		drawCircle(new Circle3D(Pos3D.ZERO,leCercle.getRayon(), leCercle.getPlan()),i1); 
		Pos3D newCommon=Pos3D.add(leCentre, translation); 
		i1.setColor(Color.RED);
		drawPoint(newCommon.getY(),newCommon.getZ(),i1); 
		i1.setColor(Color.BLACK);
		
		///Pas necessaire pour la suite, on les garde au cas ou  
		 
		for(int j=0;j<nbCercles;j++){
			if(j!=numero){
				
				DroiteSpace3D courante=intersectionsPositifPositif[numero][j]; 
				courante=courante.rotate(larot); 
				/*
				Pos3D inter0=pointsInterPositifPositif[numero][j][0]; 
				Pos3D inter1=pointsInterPositifPositif[numero][j][1]; 
				System.out.println("***************\n La droite "); 
				System.out.println(numero+" "+j+" "+courante);
				System.out.println(inter0+" "+courante.belongs(inter0)); 
				System.out.println(inter1+" "+courante.belongs(inter1)); 
				System.out.println(inter0.rotate(larot)); 
				System.out.println(inter1.rotate(larot));
				*/
				
				/*
				inter0=inter0.rotate(larot); 
				inter1=inter1.rotate(larot);
				inter0=Pos3D.add(inter0,translation); 
				inter1=Pos3D.add(inter1,translation); 
				
				drawPoint(inter0.getY(),inter0.getZ(),i1); 
				drawPoint(inter1.getY(),inter1.getZ(),i1);
				*/ 
				/*
				ArrayList<Pos3D> lesBords=intersectCadre(2*(-mu-c-marge),2*(mu+c+marge),2*(-mu-c-marge),2*(mu+c+marge), courante);
				if(lesBords.size()==2){ // tracer la ligne
					Pos3D s1=Pos3D.add(lesBords.get(0),translation); 
					Pos3D s2=Pos3D.add(lesBords.get(1),translation); 
					drawLine(s1.getY(),s1.getZ(),s2.getY(),s2.getZ(),i1);
					 
				}// if lesBords
				*/
			}	// if j
				
			} // for j
			
		// Tracer la limite de la lunule en vert
		// Todo : tracer une ligne joignant les points successifs ? 
		// ou bien des points plus petits
		i1.setColor(Color.GREEN);
		for(int j=0;j<nbCercles;j++){
			if(j!=numero){
				
				Pos3D inter0=pointsInterPositifPositif[j][numero][0]; 
				Pos3D inter1=pointsInterPositifPositif[j][numero][1];
				 
				
				inter0=inter0.rotate(larot); 
				inter1=inter1.rotate(larot);
				inter0=Pos3D.add(inter0,translation); 
				inter1=Pos3D.add(inter1,translation); 
				drawPoint(inter0.getY(),inter0.getZ(),i1); 
				drawPoint(inter1.getY(),inter1.getZ(),i1); 
			}	
				
			}
		
			// TODO : les droites d'intersection des negatifs
		for(int j=0;j<nbCercles;j++){
			
				
				DroiteSpace3D courante=intersectionsPositifNegatif[numero][j]; 
				courante=courante.rotate(larot); 
				
				ArrayList<Pos3D> lesBords=intersectCadre(2*(-mu-c-marge),2*(mu+c+marge),2*(-mu-c-marge),2*(mu+c+marge), courante);
				if(lesBords.size()==2){ // tracer la ligne
					Pos3D s1=Pos3D.add(lesBords.get(0),translation); 
					Pos3D s2=Pos3D.add(lesBords.get(1),translation); 
					
					double pyPrint=s1.getY()+0.19*(s2.getY()-s1.getY()); 
					double pzPrint=s1.getZ()+0.19*(s2.getZ()-s1.getZ()); 
					i1.setColor(Color.BLACK);
					drawChaine(pyPrint,pzPrint,"Neg "+j,i1); 
					i1.setColor(Color.RED);
					drawLine(s1.getY(),s1.getZ(),pyPrint,pzPrint,i1); 
				}// if lesBords
				
		
				
			} // for j
		
		
		i1.setColor(Color.BLACK);
		
			gamma.show(); 
			fs.saveAsPng("/tmp/"+name+numero+".png"); 
			//gamma.close(); 
			
			
		}

	
	public void printNegatif(Circle3D leCercle,Pos3D leCentre,CoupleDAngles larot,int numero,String name){
	    name="dupin/dir4/Negatif"+name;
	    
		setBounds(2*(-mu-c-marge),2*(mu+c+marge),2*(-mu-c-marge),2*(mu+c+marge)); 
		setCoefs();
		
		ImagePlus gamma=NewImage.createRGBImage (name+numero,X,Y, 1, NewImage.FILL_WHITE);	
		ImageProcessor i1=gamma.getProcessor();
		FileSaver fs=new FileSaver(gamma); 
		i1.setColor(Color.BLACK);
		i1.drawString("Negatif "+numero,20,20); 
		//Pos3D translation=Pos3D.sub(Pos3D.ZERO,leCercle.getCenter());
		Pos3D translation=new Pos3D(0,-leCercle.getCenter().getY(),-leCercle.getCenter().getZ());
		drawCircle(new Circle3D(Pos3D.ZERO,leCercle.getRayon(), leCercle.getPlan()),i1); 
		Pos3D newCommon=Pos3D.add(leCentre, translation); 
		i1.setColor(Color.RED);
		drawPoint(newCommon.getY(),newCommon.getZ(),i1); 
		i1.setColor(Color.BLACK);
		
		// Tracer la limite de la lunule en Bleu
		// Todo : tracer une ligne joignant les points successifs ? 
		// ou bien des points plus petits
		i1.setColor(Color.BLUE);
		for(int j=0;j<nbCercles;j++){
			if(j!=numero){
				Pos3D inter0=pointsInterNegatifNegatif[j][numero][0]; 
				Pos3D inter1=pointsInterNegatifNegatif[j][numero][1]; 
				inter0=inter0.rotate(larot); 
				inter1=inter1.rotate(larot);
				inter0=Pos3D.add(inter0,translation); 
				inter1=Pos3D.add(inter1,translation); 
				drawPoint(inter0.getY(),inter0.getZ(),i1); 
				drawPoint(inter1.getY(),inter1.getZ(),i1); 
			}	
				
			}
		
		i1.setColor(Color.BLACK);
		for(int j=0;j<nbCercles;j++){
			if(j!=numero){
				
				DroiteSpace3D courante=intersectionsNegatifNegatif[numero][j]; 
				courante=courante.rotate(larot); 
				/*
				ArrayList<Pos3D> lesBords=intersectCadre(2*(-mu-c-marge),2*(mu+c+marge),2*(-mu-c-marge),2*(mu+c+marge), courante);
				if(lesBords.size()==2){ // tracer la ligne
					Pos3D s1=Pos3D.add(lesBords.get(0),translation); 
					Pos3D s2=Pos3D.add(lesBords.get(1),translation); 
					drawLine(s1.getY(),s1.getZ(),s2.getY(),s2.getZ(),i1); 
				}// if lesBords
				*/
			}	// if j
				
			} // for j
		
		// TODO : les droites d'intersection des negatifs
	for(int j=0;j<nbCercles;j++){
	
			
			DroiteSpace3D courante=intersectionsNegatifPositif[numero][j]; 
			courante=courante.rotate(larot); 
			
			ArrayList<Pos3D> lesBords=intersectCadre(2*(-mu-c-marge),2*(mu+c+marge),2*(-mu-c-marge),2*(mu+c+marge), courante);
			if(lesBords.size()==2){ // tracer la ligne
				Pos3D s1=Pos3D.add(lesBords.get(0),translation); 
				Pos3D s2=Pos3D.add(lesBords.get(1),translation); 
				
				double pyPrint=s1.getY()+0.19*(s2.getY()-s1.getY()); 
				double pzPrint=s1.getZ()+0.19*(s2.getZ()-s1.getZ()); 
				i1.setColor(Color.ORANGE);
				//drawLine(s1.getY(),s1.getZ(),s2.getY(),s2.getZ(),i1); 
				drawLine(s1.getY(),s1.getZ(),pyPrint,pzPrint,i1); 
				i1.setColor(Color.BLACK);
				drawChaine(pyPrint,pzPrint,"Pos "+j,i1); 
			}// if lesBords
			
	
			
		} // for j
	
	i1.setColor(Color.BLACK);
		
			gamma.show(); 
			fs.saveAsPng("/tmp/"+name+numero+".png"); 
			//gamma.close(); 
			
			
		}

		
	/** Calcule les deux points d'intersection d'une droite avec un cercle, pour le cercle de numero i
	 * et l'intersection des deux plans correspondant aux cercles i et j. 
	 *
	 * @param i
	 * @param j
	 * @return
	 */
	public Pos3D[] interDroiteCercles(int i,int j,int type){
		DroiteSpace3D courante=null; 
		CoupleDAngles rots=null; 
		Circle3D cercle=null; 
		if(type==0){
			courante=intersectionsPositifPositif[i][j];
			rots=rotations(lesPlansPositifs[i]);
			cercle=cerclesPositifs[i].getCircle3D(); 
		}
		if(type==1){
			courante=intersectionsNegatifNegatif[i][j];
			rots=rotations(lesPlansNegatifs[i]);
			cercle=cerclesNegatifs[i].getCircle3D(); 
		}
		if(type==2){
			courante=intersectionsPositifNegatif[i][j];
			rots=rotations(lesPlansPositifs[i]);
			cercle=cerclesPositifs[i].getCircle3D(); 
		}
		if(type==3){
			courante=intersectionsNegatifPositif[i][j];
			rots=rotations(lesPlansNegatifs[i]);
			cercle=cerclesNegatifs[i].getCircle3D(); 
		}
		cercle=cercle.rotate(rots); 
		courante=courante.rotate(rots); 
		
		// On est dans le plan perpendiculaire a ox
		// Il faut encore centrer
		
		Pos3D translation=new Pos3D(0,-cercle.getCenter().getY(),-cercle.getCenter().getZ());
		Pos3D translationInverse=new Pos3D(0,cercle.getCenter().getY(),cercle.getCenter().getZ());
		// Le X ne sert a rien dans la translation, il n'est pas utilise dans la suite des calculs de cette fonction
		courante=courante.translate(translation); 
	
		// On a la droite courante, un cercle centre en (X,0,0) de rayon connu
		// On cherche les deux points d'intersection de cette droite et ce cercle
		// On reecrit l'equation de la droite y=ax+b (ici y->z, x->y)
		double petitA=courante.getDirection().getZ()/courante.getDirection().getY(); 
		double petitB=courante.getPoint().getZ()-petitA*courante.getPoint().getY(); 
		double Rcarre=cercle.getRayon()*cercle.getRayon(); 
		double deltaPrime=Rcarre+petitA*petitA*Rcarre-petitB*petitB; 
		double y0=(-petitA*petitB-Math.sqrt(deltaPrime))/(1+petitA*petitA); 
		double y1=(-petitA*petitB+Math.sqrt(deltaPrime))/(1+petitA*petitA); 
		double z0=petitA*y0+petitB; 
		double z1=petitA*y1+petitB; 
		Pos3D resu[]=new Pos3D[2]; 
		
		resu[0]=new Pos3D(cercle.getCenter().getX(),y0,z0);
		resu[1]=new Pos3D(cercle.getCenter().getX(),y1,z1); 
		resu[0]=Pos3D.add(resu[0],translationInverse); 
		resu[0]=resu[0].rotateInverse(rots); 
		resu[1]=Pos3D.add(resu[1],translationInverse); 
		resu[1]=resu[1].rotateInverse(rots); 
		return resu; 
	}
	/** Calcule les angles de rotation amenant un plan parallele a un plan perpendiculaire a ox **/
	
	public CoupleDAngles rotations(Plane p){
		CoupleDAngles resu=new CoupleDAngles(); 
		if(p.getA()==0){
			if(p.getB()==0){
				resu.setAlpha(0); 
				if(p.getC()<0) resu.setBeta(Math.PI/2); else resu.setBeta(-Math.PI/2); 
				//System.out.println("resu "+resu); 
				return resu;
			}
			else // A=0 et B!=0
			 {
			 if(p.getB()<0) resu.setAlpha(Math.PI/2); else resu.setAlpha(-Math.PI/2);
			 }
			 }
	    else // A!=0; 
	    	resu.setAlpha(-Math.atan2(p.getB(),p.getA())); 
			
		// On s'occupe de beta
		double leng=Math.sqrt(p.getA()*p.getA()+p.getB()*p.getB()); 
		resu.setBeta(-Math.atan2(p.getC(),leng));
		
		//System.out.println("resu "+resu); 
		return resu; 
		}
		
	public DroiteSpace3D inter(Plane p1,Plane p2){
		if((p1.getA()==0)&&(p2.getA()!=0)){
			Plane temp=p1; p1=p2; p2=temp;
		}
		if((p1.getA()==0)&&(p2.getA()==0)){ // droite de direction (1,0,0) (ou bien plan paralleles, pas de solution)
			if((p1.getB()==0)&&(p2.getB()==0)) return null; // plans paralleles
			if((p1.getB()==0)&&(p2.getB()!=0)){
				Plane temp=p1; p1=p2; p2=temp;
			}
			// Chercher un point (x,y,z)
			double bdm=p2.getB()*p1.getD()-p1.getB()*p2.getD(); 
			double cbm=p2.getC()*p1.getB()-p1.getC()*p2.getB(); 
			double zconstante=bdm/cbm;
			double yconstante=-p1.getC()/p1.getB()*zconstante-(p1.getD()/p1.getB()); 
			Pos3D lepoint=new Pos3D(0,yconstante,zconstante); 
			Pos3D ladirection=new Pos3D(1,0,0);
			return new DroiteSpace3D(lepoint,ladirection); 
		}
		
		double ab=p1.getA()*p2.getB()-p1.getB()*p2.getA(); 
		if(ab==0) // vecteur directeur dans le plan xOy (composante nulle selon z)
		{
			double bdm=p2.getB()*p1.getD()-p1.getB()*p2.getD(); 
			double cbm=p2.getC()*p1.getB()-p1.getC()*p2.getB(); 
			double zconstante=bdm/cbm;
			double yconstante=-1/p1.getB()*(p1.getC()*zconstante-p1.getD());
			Pos3D lepoint=new Pos3D(0,yconstante,zconstante);
			Pos3D ladirection=new Pos3D(1,-p1.getA()/p1.getB(),0); 
			return new DroiteSpace3D(lepoint,ladirection); 
		}
		double adm=p2.getA()*p1.getD()-p1.getA()*p2.getD(); 
		double acm=p2.getA()*p1.getC()-p1.getA()*p2.getC();
		double yconstante=adm/ab; 
		double zconstante=0; 
		double xconstante=-p1.getB()/p1.getA()*(adm/ab)-p1.getD()/p1.getA(); 
		double zcoef=1; 
		double ycoef=acm/ab; 
		double xcoef=-p1.getB()/p1.getA()*(acm/ab)-p1.getC()/p1.getA(); 
		Pos3D lepoint=new Pos3D(xconstante,yconstante,zconstante);
		Pos3D ladirection=new Pos3D(xcoef,ycoef,zcoef); 
		return new DroiteSpace3D(lepoint,ladirection); 
	}
	
		/* Trouver l'intersection de la droite avec un des quatres cotes de l'image
		 * retourne null si parallele ou en dehors de l'image. 
		 * on ne s'occupe pas de la valeur de x (tout se passe dans le plan perpendiculaire
		 * a l'axe Ox)
		 */
		public Pos3D coteVsDroite(Pos3D A,Pos3D B,DroiteSpace3D D){
			double yv=D.getDirection().getY(); 
			double zv=D.getDirection().getZ(); 
			double ya=A.getY(); 
			double za=A.getZ(); 
			double yb=B.getY(); 
			double zb=B.getZ(); 
			double y0=D.getPoint().getY(); 
			double z0=D.getPoint().getZ(); 
			double det=-zv*(ya-yb)+yv*(za-zb); 
			if(Math.abs(det)<1e-6) return null; 
			double detAlpha=-zv*(y0-yb)+yv*(z0-zb);
			double alpha=detAlpha/det; 
			if ((alpha<0)||(alpha>1)) return null; 
			// on s'en fout de X, on va tracer une droite dans un plan
			double ny=alpha*ya+(1-alpha)*yb; 
			double nz=alpha*za+(1-alpha)*zb;
			return new Pos3D(0,ny,nz); 
		}
		
		public ArrayList<Pos3D> intersectCadre(double ymin,double ymax,double zmin,double zmax,DroiteSpace3D Q){
			ArrayList<Pos3D> resu=new ArrayList<Pos3D>(); 
			Pos3D A=new Pos3D(0,ymin,zmin); 
			Pos3D B=new Pos3D(0,ymin,zmax); 
			Pos3D C=new Pos3D(0,ymax,zmin); 
			Pos3D D=new Pos3D(0,ymax,zmax); 
			if(coteVsDroite(A,B,Q)!=null) resu.add(coteVsDroite(A,B,Q)); 
			if(coteVsDroite(A,C,Q)!=null) resu.add(coteVsDroite(A,C,Q)); 
			if(coteVsDroite(B,D,Q)!=null) resu.add(coteVsDroite(B,D,Q)); 
			if(coteVsDroite(C,D,Q)!=null) resu.add(coteVsDroite(C,D,Q)); 
			return resu; 
		}
	
	public void run(String arg) {
	
		primeIP = new ColorProcessor(X,Y);
		
		
		double limit=1; 
		double lmoins=-1;
	
		setBounds(lmoins,limit,lmoins,limit); 
		setCoefs(); 
		
		
		
		Polygon background=new Polygon(new int[]{0,0,X,Y},new int[]{0,X,Y,0},4);
		primeIP.setColor(Color.WHITE);
		
		primeIP.fillPolygon(background);
		
		
		primeIP.setFont(new Font(null,Font.ITALIC,60));
		primeIP.setColor(Color.BLACK);
		primeIP.setLineWidth(2); 
		

		setProcessor("Verifying", primeIP);
		
		
		primeIP.setColor(Color.BLACK);
		primeIP.setLineWidth(5);
		
		a=5; 
		mu=3; 
		c=1; // 1
		DupinCyclide dc=new DupinCyclide(a,mu,c); 
		pointCommun=new Pos3D(a*c/mu,0,0); 
		Pos3D pointTest=new Pos3D(5,12,89); 
		//nbCercles=10; 
		cerclesPositifs=new CiclydeVillarceauCircle[nbCercles]; 
		lesPlansPositifs=new Plane[nbCercles]; 
		intersectionsPositifPositif=new DroiteSpace3D[nbCercles][nbCercles]; 
		pointsInterPositifPositif=new Pos3D[nbCercles][nbCercles][2];
		
		cerclesNegatifs=new CiclydeVillarceauCircle[nbCercles]; 
		lesPlansNegatifs=new Plane[nbCercles]; 
		intersectionsNegatifNegatif=new DroiteSpace3D[nbCercles][nbCercles]; 
		pointsInterNegatifNegatif=new Pos3D[nbCercles][nbCercles][2];
		
		intersectionsNegatifPositif=new DroiteSpace3D[nbCercles][nbCercles]; 
		pointsInterNegatifPositif=new Pos3D[nbCercles][nbCercles][2];
		
		intersectionsPositifNegatif=new DroiteSpace3D[nbCercles][nbCercles]; 
		pointsInterPositifNegatif=new Pos3D[nbCercles][nbCercles][2];
		
		for (int i=0;i<nbCercles;i++){
		cerclesPositifs[i]=new CiclydeVillarceauCircle(dc,2*i*Math.PI/nbCercles,1);
		lesPlansPositifs[i]=cerclesPositifs[i].getPlane(); 
		cerclesNegatifs[i]=new CiclydeVillarceauCircle(dc,2*i*Math.PI/nbCercles,-1);
		lesPlansNegatifs[i]=cerclesNegatifs[i].getPlane(); 
		
		}
		for(int i=0;i<nbCercles;i++){
			for(int j=0;j<nbCercles;j++){
					intersectionsNegatifPositif[i][j]=inter(lesPlansPositifs[i],lesPlansNegatifs[j]); 
					intersectionsPositifNegatif[i][j]=inter(lesPlansNegatifs[i],lesPlansPositifs[j]); 
				if(i!=j){
					intersectionsPositifPositif[i][j]=inter(lesPlansPositifs[i],lesPlansPositifs[j]); 
					intersectionsNegatifNegatif[i][j]=inter(lesPlansNegatifs[i],lesPlansNegatifs[j]); 
					
				}
				else{
					intersectionsPositifPositif[i][j]=null;
					intersectionsNegatifNegatif[i][j]=null;
					
				}
			}
		}
		
		for(int i=0;i<nbCercles;i++){
			for(int j=0;j<nbCercles;j++){
				Pos3D resu[]=null; 
				if(i!=j){
					resu=interDroiteCercles(i,j,0); 
					pointsInterPositifPositif[i][j][0]=resu[0]; 
					pointsInterPositifPositif[i][j][1]=resu[1]; 
					
					resu=interDroiteCercles(i,j,1); 
					pointsInterNegatifNegatif[i][j][0]=resu[0]; 
					pointsInterNegatifNegatif[i][j][1]=resu[1]; 
					
					resu=interDroiteCercles(i,j,2); 
					pointsInterPositifNegatif[i][j][0]=resu[0]; 
					pointsInterPositifNegatif[i][j][1]=resu[1]; 
					
					resu=interDroiteCercles(i,j,3); 
					pointsInterNegatifPositif[i][j][0]=resu[0]; 
					pointsInterNegatifPositif[i][j][1]=resu[1]; 
					
					
					// TODO : interdroite (i,j,2) (i,j,3)
				}
				
			}
		}
		for (int i=0;i<nbCercles;i++){
			Plane lePlan=cerclesPositifs[i].getPlane();
			CoupleDAngles rots=rotations(lePlan);
			
			Pos3D point=pointCommun.rotate(rots); 
			Circle3D cercle=cerclesPositifs[i].getCircle3D(); 
			cercle=cercle.rotate(rots); 
			printPositif(cercle,point,rots,i,"ABC");
			
			lePlan=cerclesNegatifs[i].getPlane();
			rots=rotations(lePlan);
			
			point=pointCommun.rotate(rots); 
			cercle=cerclesNegatifs[i].getCircle3D(); 
			cercle=cercle.rotate(rots); 
			printNegatif(cercle,point,rots,i,"DEF");
			
		
		}
		System.out.println("fini"); 
		
		
	
}
	
}
	